package com.tools.web.work.excel.poi;

import com.tools.common.container.RowKit;
import com.tools.common.object.Note;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

/**
 * Excel 表头数据的包装类实例
 * 分别存储 Excel 的 【表头名称 - 对象属性名称 - 顺序 - 每一列的宽度】
 * 等数据
 * */
@Note("Excel 表头数据的包装类实例" +
        "分别存储 Excel 的 【表头名称 - 对象属性名称 - 顺序 - 每一列的宽度】 等数据")
public final class ExcelHead {

    @Note("表头数据项")
    private List<ExcelField> headRows;

    @Note("表头的最大行数")
    private int maxHeadRowNum;

    /* ************************************************************************************************************
     *
     *      构造器
     *
     * ************************************************************************************************************
     * */

    public ExcelHead() {}

    public ExcelHead(Class<?> excelEntityClass) {
        this.headRows = ExcelKit.buildExcelFieldListByAnnotation(excelEntityClass);
        for (ExcelField ef : this.headRows) {
            this.private_calcMaxRowNum(ef.getNames().length);
        }
    }

    public static ExcelHead of() {
        return new ExcelHead();
    }

    public static ExcelHead of(Class<?> excelEntityClass) {
        return new ExcelHead(excelEntityClass);
    }

    /* ************************************************************************************************************
     *
     *      其他方法
     *
     * ************************************************************************************************************
     * */

    @Note("被同包的工具类使用，用于获取所有的表头数据用于构建 Excel")
    List<ExcelField> getHeadRows() {
        return headRows;
    }

    public int getMaxHeadRowNum() {
        return maxHeadRowNum;
    }

    public int getHeadCount() {
        return headRows == null ? 0 : headRows.size();
    }

    @Override
    public String toString() {
        return "ExcelHead{" +
                "maxHeadRowNum=" + maxHeadRowNum +
                ", headRows=" + headRows +
                '}';
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ExcelHead excelHead = (ExcelHead) o;
        return maxHeadRowNum == excelHead.maxHeadRowNum && Objects.equals(headRows, excelHead.headRows);
    }

    @Override
    public int hashCode() {
        return Objects.hash(headRows, maxHeadRowNum);
    }

    /* ************************************************************************************************************
     *
     *      私有逻辑
     *
     * ************************************************************************************************************
     * */

    @Note("懒加载表头容器")
    private void private_lazyLoad() {
        if(this.headRows != null) return;
        synchronized (this) {
            if(this.headRows != null) return;
            this.headRows = new ArrayList<>();
        }
    }


    @Note("计算最大行数")
    private void private_calcMaxRowNum(int num) {
        if(this.maxHeadRowNum < num) {
            this.maxHeadRowNum = num;
        }
    }


    @Note("将 Iterable 转为字符串数组，并设置表头所占的最大行数")
    private String[] private_toStringArray(Iterable<String> iterable) {
        if(iterable == null) {
            this.private_calcMaxRowNum(1);
            return new String[] {""};
        }
        int size = RowKit.getIterableSize(iterable);
        if(size == 0) {
            this.private_calcMaxRowNum(1);
            return new String[] {""};
        }
        String[] names = new String[size];
        int i = 0;
        for (String name : iterable) {
            names[i] = name;
            i++;
        }
        this.private_calcMaxRowNum(i);
        return names;
    }

    /* ************************************************************************************************************
     *
     *      公共方法
     *
     * ************************************************************************************************************
     * */


    public synchronized ExcelHead add(String field, String... names) {
        return this.add(ExcelField.DEFAULT_HEAD_WIDTH, false, field, names);
    }

    public synchronized ExcelHead add(boolean sameValueMerge, String field, String... names) {
        return this.add(ExcelField.DEFAULT_HEAD_WIDTH, sameValueMerge, field, names);
    }

    public synchronized ExcelHead add(int headWidth, String field, String... names) {
        return this.add(headWidth, false, field, names);
    }

    public synchronized ExcelHead add(int headWidth, boolean sameValueMerge, String field, String... names) {
        private_lazyLoad();
        this.headRows.add(new ExcelField(headWidth, sameValueMerge, field, names));
        private_calcMaxRowNum(names.length);
        return this;
    }

    public synchronized ExcelHead add(String field, Iterable<String> names) {
        return this.add(ExcelField.DEFAULT_HEAD_WIDTH, false, field, names);
    }

    public synchronized ExcelHead add(boolean sameValueMerge, String field, Iterable<String> names) {
        return this.add(ExcelField.DEFAULT_HEAD_WIDTH, sameValueMerge, field, names);
    }

    public synchronized ExcelHead add(int headWidth, String field, Iterable<String> names) {
        return this.add(headWidth, false, field, names);
    }

    public synchronized ExcelHead add(int headWidth, boolean sameValueMerge, String field, Iterable<String> names) {
        private_lazyLoad();
        String[] namesArray = this.private_toStringArray(names);
        this.headRows.add(new ExcelField(headWidth, sameValueMerge, field, namesArray));
        private_calcMaxRowNum(namesArray.length);
        return this;
    }

    public synchronized ExcelHead set(int index, String field, String... names) {
        return this.set(index, ExcelField.DEFAULT_HEAD_WIDTH, false, field, names);
    }

    public synchronized ExcelHead set(int index, boolean sameValueMerge, String field, String... names) {
        return this.set(index, ExcelField.DEFAULT_HEAD_WIDTH, sameValueMerge, field, names);
    }

    public synchronized ExcelHead set(int index, int headWidth, String field, String... names) {
        return this.set(index, headWidth, false, field, names);
    }

    public synchronized ExcelHead set(int index, int headWidth, boolean sameValueMerge, String field, String... names) {
        private_lazyLoad();
        this.headRows.add(index, new ExcelField(headWidth, sameValueMerge, field, names));
        private_calcMaxRowNum(names.length);
        return this;
    }

    public synchronized ExcelHead set(int index, String field, Iterable<String> names) {
        return this.set(index, ExcelField.DEFAULT_HEAD_WIDTH, false, field, names);
    }

    public synchronized ExcelHead set(int index, boolean sameValueMerge, String field, Iterable<String> names) {
        return this.set(index, ExcelField.DEFAULT_HEAD_WIDTH, sameValueMerge, field, names);
    }

    public synchronized ExcelHead set(int index, int headWidth, String field, Iterable<String> names) {
        return this.set(index, headWidth, false, field, names);
    }

    public synchronized ExcelHead set(int index, int headWidth, boolean sameValueMerge, String field, Iterable<String> names) {
        private_lazyLoad();
        String[] namesArray = this.private_toStringArray(names);
        this.headRows.add(index, new ExcelField(headWidth, sameValueMerge, field, namesArray));
        private_calcMaxRowNum(namesArray.length);
        return this;
    }


    public synchronized ExcelField get(int index) {
        if(this.headRows == null || this.headRows.isEmpty()) return null;
        int size = this.headRows.size();
        if(index < 0 || index >= size) return null;
        return this.headRows.get(index);
    }


    public synchronized ExcelHead clear() {
        if(this.headRows == null || this.headRows.isEmpty()) return this;
        this.headRows.clear();
        this.maxHeadRowNum = 0;
        return this;
    }
}
